package com.water.guider

import android.animation.Animator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.FrameLayout
import androidx.annotation.AttrRes
import com.itsite.guider.R
import com.water.guider.highlight.IHighlight
import com.water.guider.position.IPosition
import com.water.guider.utils.Utils

/**
 * 引导页的根布局视图.
 */
class GuiderView : FrameLayout, OnGlobalLayoutListener {

    constructor(context: Context) : this(context, null)

    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, -1)

    constructor(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr: Int = -1) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        tag = TAG
        //关闭当前view的硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE, null)
        isClickable = true
        //ViewGroup默认设定为true，会使onDraw方法不执行，如果复写了onDraw(Canvas)方法，需要清除此标记
        setWillNotDraw(false)
    }

    /**
     * 当前引导页
     */
    var currentGuide: Guide? = null

    var index = 0

    var onGuiderStartListeners: List<OnGuiderStartListener>? = null

    var onGuiderStopListener: List<OnGuiderStopListener>? = null

    var guides: MutableList<Guide> = mutableListOf()
        private set

    /**
     * 当前模式.
     */
    var mode = Guider.MODE_NEXT

    var jumpGravity = JumpGravity.NONE

    /**
     * 绘制高亮区域的画笔
     */
    private val mPaint: Paint = Paint().apply {
        isAntiAlias = true
        color = -0x1
        xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
        flags = Paint.ANTI_ALIAS_FLAG
        //设置画笔遮罩滤镜,可以传入BlurMaskFilter或EmbossMaskFilter，前者为模糊遮罩滤镜而后者为浮雕遮罩滤镜
        //这个方法已经被标注为过时的方法了，如果你的应用启用了硬件加速，你是看不到任何阴影效果的
        maskFilter = BlurMaskFilter(3F, BlurMaskFilter.Blur.INNER)
    }

    /**
     * 顶部跳过图标.
     */
    private val jumpBitmap by lazy {
        BitmapFactory.decodeResource(resources, R.mipmap.ic_jump_guide)
    }

    private val bitmapPaint = Paint()

    override fun onGlobalLayout() {}

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        reposition()
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        super.onLayout(changed, left, top, right, bottom)
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            if (child.visibility == GONE) {
                continue
            }
            when (mode) {
                Guider.MODE_TOGETHER -> layoutChild(child, guides[i])
                else -> currentGuide?.let {
                    layoutChild(child, it)
                }
            }
        }
        mHeight = height
    }

    private var mHeight = 0

    override fun onDraw(canvas: Canvas) {

        when (mode) {
            Guider.MODE_TOGETHER -> {
                for (guide in guides) {
                    drawGuide(canvas, guide)
                }
            }
            else -> currentGuide?.let {
                drawGuide(canvas, it)
            }
        }

        drawJumpBitmap(canvas)
    }

    /**
     * 绘制引导页中的高亮区域
     */
    private fun drawGuide(canvas: Canvas, guide: Guide) {
        canvas.drawColor(guide.backgroundColor)
        guide.highlight.draw(
            canvas, mPaint, guide.x, guide.y,
            if (guide.animator == null) 0 else guide.animator!!.animatedValue as Int
        )
    }

    /**
     * 重写触摸事件.
     */
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (isClickJumpMotionEvent(event)) {
            Log.i(TAG, "onTouchEvent: isClickJumpMotionEvent")
            dismiss()
            return true
        } else {
            if (guides.isNotEmpty()) {
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> if (mode == Guider.MODE_NEXT) {
                        removeView(currentGuide!!.view)
                        ++index
                        if (index == guides.size) {
                            dismiss()
                        }
                    }
                    MotionEvent.ACTION_UP -> if (mode == Guider.MODE_NEXT) {
                        if (index < guides.size) {
                            currentGuide = guides[index]
                            currentGuide?.let {
                                showGuide(it)
                            }
                        }
                    } else if (mode == Guider.MODE_TOGETHER) {
                        dismiss()
                    }
                    else -> {
                    }
                }
                return true
            }
            return super.onTouchEvent(event)
        }
    }

    /**
     *该方法是View添加到了Window窗口之后的一个回调
     */
    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        if (onGuiderStartListeners != null) {
            for (onStartListener in onGuiderStartListeners!!) {
                onStartListener.onStart()
            }
        }
        if (mode == Guider.MODE_NEXT) {
            if (guides.isNotEmpty()) {
                currentGuide = guides[index]
                currentGuide?.let {
                    showGuide(it)
                }
            } else {
                Log.d(TAG, "the GuiderView has no guide!")
            }
        } else if (mode == Guider.MODE_TOGETHER) {
            for (guide in guides) {
                showGuide(guide)
            }
        }
    }

    /**
     * 窗口移除的回调函数
     */
    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        if (onGuiderStopListener != null) {
            for (onStopListener in onGuiderStopListener!!) {
                onStopListener.onStop()
            }
        }
    }

    private fun reposition() {
        for (guide in guides) {
            val pointView = guide.pointView
            if (pointView != null) {
                guide.pointView = pointView
                val highlight = guide.highlight
                highlight.width = pointView.width
                highlight.height = pointView.height
                highlight.init()
                val animator = guide.animator
                animator?.setIntValues(0, highlight.max)
            }
        }
    }

    private fun reposition(guide: Guide?) {
        val pointView = guide!!.pointView
        if (pointView != null) {
            guide.pointView = pointView
            val highlight = guide.highlight
            if (highlight != null) {
                highlight.width = pointView.width
                highlight.height = pointView.height
                highlight.init()
                val animator = guide.animator
                animator?.setIntValues(0, highlight.max)
            }
        }
    }

    private fun layoutChild(child: View, guide: Guide) {

        val position: IPosition = guide.position
        val x: Int = guide.x
        val y: Int = guide.y
        val highlight: IHighlight = guide.highlight

        val lp = child.layoutParams as LayoutParams
        val width = child.width
        val height = child.height

        val childLeft = position.left(x, highlight.width, width) + lp.leftMargin
        val childTop = position.top(y, highlight.height, height) + lp.topMargin

        val childRight = childLeft + width - lp.rightMargin
        val childBottom = childTop + height - lp.bottomMargin
        child.layout(childLeft, childTop, childRight, childBottom)
    }

    /**
     * 跳过按钮的展示区域
     */
    private val jumpRectF = RectF()

    private val srcRect = Rect()

    /**
     * 判断触摸区域是否为跳过按钮,true:触发跳过按钮的点击事件.
     */
    private fun isClickJumpMotionEvent(event: MotionEvent): Boolean =
        if (jumpGravity == JumpGravity.TOP) event.x >= jumpRectF.left - JUMP_DEVIATION
                && event.x <= jumpRectF.right + JUMP_DEVIATION
                && event.y >= jumpRectF.top - JUMP_DEVIATION
                && event.y <= jumpRectF.bottom + JUMP_DEVIATION
        else event.x >= jumpRectF.left - JUMP_DEVIATION
                && event.x <= jumpRectF.right + JUMP_DEVIATION
                && event.y >= jumpRectF.top - jumpRectF.height() * 2 - JUMP_DEVIATION
                && event.y <= jumpRectF.bottom + JUMP_DEVIATION

    private val mMatrix = Matrix().apply {
        jumpBitmap.apply {
            jumpRectF.left = resources.getDimension(R.dimen.dp_20)
            jumpRectF.top = resources.getDimension(R.dimen.dp_40)
            jumpRectF.right = width.toFloat()
            jumpRectF.bottom = height.toFloat()
        }
        this.postTranslate(jumpRectF.left, jumpRectF.top)
        this.postScale(0.8F, 0.75F)
    }

    private val bMatrix = Matrix().apply {
        /*jumpBitmap.apply {
            //val parentHeight = this@GuiderView.height.toFloat()

            jumpRectF.left = resources.getDimension(R.dimen.dp_20)
            jumpRectF.top = mHeight - this.height.toFloat()
            jumpRectF.right = width.toFloat()
            jumpRectF.bottom = jumpRectF.top + this.height * 4
            Log.i(TAG, "[jumpRectF.top]: ${jumpRectF.top}")
            Log.i(TAG, "[jumpRectF.bottom]: ${jumpRectF.bottom}")
            Log.i(TAG, "mHeight: $mHeight")
        }*/

        Log.i(TAG, "(bMatrix,jumpRectF.top): ${jumpRectF.top}")
        //this.postTranslate(jumpRectF.left, jumpRectF.top*5)
        //this.postTranslate(jumpRectF.left, jumpRectF.bottom)
        //this.postScale(0.8F, 0.75F)
    }

    /**
     * 绘制跳过按钮
     */
    private fun drawJumpBitmap(canvas: Canvas) {
        mHeight = height
        Log.i(TAG, "drawJumpBitmap,mHeight: $mHeight")
        val jBitmapHeight = jumpBitmap.height.toFloat()

        when (jumpGravity) {

            JumpGravity.TOP -> {
                canvas.drawBitmap(jumpBitmap, mMatrix, bitmapPaint)
            }

            //JumpGravity.BOTTOM, -> canvas.drawBitmap(jumpBitmap, bMatrix, bitmapPaint)

            else -> {
                jumpRectF.run {
                    left = resources.getDimension(R.dimen.dp_20)
                    right = jumpBitmap.width.toFloat()

                    top = mHeight - (jBitmapHeight * 0.5F).toInt().toFloat()
                    bottom = jumpRectF.top + jBitmapHeight * 1

                    Log.i(
                        TAG, "jumpRectF: (left:$left)," +
                                "(right:$right)," +
                                "(top:$top)," +
                                "(bottom:$bottom)"
                    )
                }

                bMatrix.reset()
                bMatrix.postTranslate(jumpRectF.left, jumpRectF.bottom)
                bMatrix.postScale(0.8F, 0.8F)
                canvas.drawBitmap(jumpBitmap, bMatrix, bitmapPaint)
            }
        }

        //canvas.drawBitmap(jumpBitmap, jumpRectF.left, jumpRectF.top, bitmapPaint)

    }

    fun dismiss() {
        removeAllViews()
        if (parent != null && parent is ViewGroup) {
            (parent as ViewGroup).removeView(this)
        }
    }

    val isVisible: Boolean
        get() = if (parent != null && parent is ViewGroup) {
            (parent as ViewGroup).findViewWithTag<View>(TAG) != null
        } else false

    private fun showGuide(guide: Guide) {
        reposition(guide)
        if (guide.view != null) {
            addView(
                guide.view, LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT
                )
            )
        }

        if (guide.animator == null) {
            return
        }

        guide.animator!!.addUpdateListener {
            postInvalidate()
        }

        guide.animator!!.addListener(object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
                if (guide.onGuideListener != null) {
                    guide.onGuideListener?.onStart(guide)
                }
            }

            override fun onAnimationEnd(animation: Animator) {
                if (guide.onGuideListener != null) {
                    guide.onGuideListener?.onStop(guide)
                }
            }

            override fun onAnimationCancel(animation: Animator) {

            }

            override fun onAnimationRepeat(animation: Animator) {

            }
        })
        guide.animator?.start()
    }

    fun setOnGuiderStopListeners(onStopListeners: List<OnGuiderStopListener>?) {
        onGuiderStopListener = onStopListeners
    }

    fun setGuides(guides: List<Guide>) {
        this.guides.clear()
        for (guide in guides) {
            if (guide.viewId != 0) {
                guide.view = inflate(context, guide.viewId, null)
                guide.onConvertListener?.convert(BaseViewHolder(guide.view), this)
            }
            this.guides.add(guide)
        }
    }

    companion object {
        val TAG: String = GuiderView::class.java.name

        /**
         * 跳过按钮的触摸区域误差值
         */
        private const val JUMP_DEVIATION = 50
    }

}